Developer guide for product bundles
The Mercury Product Bundle feature provides all functionality needed to incorporate product bundles in your e-commerce site. Product bundles can contain any number of products, and by default, Mercury provides the necessary functionality. However, if you need to implement your own solution for getting product bundle data, Mercury provides extension points, see the Extension points section.
Design
Model
A bundle has a reference id, title, description, and a (discount) price. Products in a bundle are described by bundle items. A bundle item has a title, quantity, price, and an (optional) image. One of the bundle items is marked as "main" item. This information is used for presentation, the main item is shown differently than the others.
A bundle reference id is used to uniquely identify a bundle. In the current implementation the reference id is the product id, variant id plus a suffix for the bundle: {productid}_{bundleid}
or in case of a variant: {productid}_{variantid}_{bundleid}
. For example: dr001_101_1, where dr001 is the product id, 101 is the variant id and 1 is the bundle id. The bundle id only needs to be unique within the product or variant. If the default reference separator: _
conflicts with your product ids or variant ids, its possible to change the separator value with the following Sitecore configuration setting: Mercury.ProductBundles.ReferenceSeparator
.
Title and description are useful fields for marketeers to specify custom names for bundles and its items. Prices are calculated, based on a absolute or relative discount amount, from the original price.
A bundle may have a directly related product. If so, this relation identifies the product in the catalog that is composed of all bundle items (i.e. a SKU). Note that in this case, bundle items may still be useful as they indicate the products the SKU is composed of.
The complete UML class diagram for Product Bundles is shown below.
Note that in code, a second, next to above model, exists that is optimized for persistent storage.
To summarize, there are two ways of storing a product bundle:
- without direct product relation: bundle does not relate to a product, but contains a collection of items that relate to a product or a variant
- with direct product relation: bundle relates to a product (i.e. a SKU) and contains items that relate to a product
Defining a product bundle
Bundle data is stored as JSON in the custom property "Bundles" for a Commerce product or in a "Variant_Bundles" property for a Commerce product variant. These properties need to be added to the commerce schema of the catalog. The JSON schema is based on the Bundle persistence model. An example of a product bundle in JSON:
[
{
"referenceId": "DR-012_1",
"title": "Cola and Juice bundle",
"description": "Cola and Juice product bundle",
"priceInformation": {
"type": "fixedprice",
"value": 2.50,
"description": "Bundle price: 2.50"
},
"bundleItems": [
{
"isMain": true,
"productID": "DR-012"
},
{
"title": "Lemon Juice",
"isMain": false,
"productID": "DR-016",
"variantID": "DR-016-02"
}
]
}
]
An example of a product with a related product in the catalog, i.e. a SKU, is:
{
"referenceId": "DR-012_3",
"title": "Celery, Cucumber and Carrot combi",
"productID": "VEBU-001",
"bundleItems": [
{
"title": "Celery 3x",
"isMain": true,
"productID": "VE-010",
"quantity": 3
},
{
"title": "Cucumber 3x",
"isMain": false,
"productID": "VE-013",
"quantity": 3
},
{
"title": "Carrot 3x",
"isMain": false,
"productID": "VE-008",
"quantity": 3
}
]
}
The productID
in above example indicates the product in the catalog that represents the SKU.
As seen in above examples, for storage a slighty modified persistence
model, which e.g. doesn't contain the full product data, is used. One should use the mercury.translate.bundleToViewModel
pipeline to convert the persistence
model to a full model.
In a production setup the bundle data should be imported from e.g. a back-office system that contains product bundle definitions. Mercury does currently not provide bundle data import functionality.
Functionality
Add product bundle to cart
A product bundle is added to the cart by using Mercury Checkout. The mercury.addBundleToCart
pipeline connects to the Mercury Checkout service and this pipeline can be used to customize this functionality. The pipeline is exposed to the React UI via the REST API that calls the Mercury.Foundation.ProductBundles
service.
Display product bundles in cart
The Product Bundle Javascript bundle registers itself to Mercury Checkout for displaying product bundles line items. In this way the cart will use the registered cart
React components for rendering product bundle line items.
Remove the bundle from the cart
This works out-of-the-box with the existing Mercury Checkout functionality.
Buy a bundle
Creating an order from a cart is standard Mercury Checkout functionality; this works out-of-the-box.
See bundle in an order
For displaying product bundle order line items the same mechanism as for cart line items is used: the Javascript bundle registers itself to the Mercury Checkout bundle.
React components
A product bundles view is generated using the React components located in UI/components
. The components are structured as follows:
productbundles.jsx
bundles
bundle.jsx
bundleitems.jsx
...
item
bundleitem.jsx
...
cart
maincartlineitem.jsx
orderlineitem.jsx
At the top level productbundles.jsx
can be used to display a collection of product bundles. Each bundle is displayed by bundle/bundle.jsx
, and each item in a bundle is displayed by bundle/item/bundleitem.jsx
. This structure closely follows the model and adheres to the atomic design principle that components should consist of (replaceable) building blocks.
Extension points
Provided pipelines
The Product Bundles feature provides the following pipelines as extension points for customization:
mercury.getProductBundles
mercury.getVisibleProductBundles
mercury.getProductBundlesByReference
mercury.addBundleToCart
mercury.translate.bundleToViewModel
mercury.getProductBundles
This pipeline retrieves the product bundles of a specific product. Mercury provides a default implementation for the processors. These processors can be replaced with a custom implementation.
The following processors are available:
GetProductBundlesFromProductField
: Get product bundles from the fieldBundles
of a product.ExcludeOutOfStockBundles
: Excludes out of stock product bundles from the result.CalculateBundlePrices
: Calculate and set the prices of the products bundles.
mercury.getVisibleProductBundles
This pipeline retrieves the product bundles of a specific product that should be displayed. This pipeline is similar to mercury.getProductBundles
but it can be used to filter out bundles that should not be shown on product pages, e.g. to exclude bundles without stock.
Mercury provides a default implementation for the processors. These processors can be replaced with a custom implementation.
The following processors are available:
GetProductBundlesFromProductField
: Get product bundles from the fieldBundles
of a product.ExcludeOutOfStockBundles
: Excludes out of stock product bundles from the result.CalculateBundlePrices
: Calculate and set the prices of the products bundles.
mercury.getProductBundlesByReference
Loads a product bundle by the given reference id, e.g. the reference id set in the ReferenceID
field on the Bundle
class.
mercury.addBundleToCart
Adds a product bundle to the cart using the Mercury Checkout Foundation.
mercury.translate.bundleToViewModel
Loads the complete product bundle model from the given persistence storage model.
Used pipelines
Product Bundles uses several pipelines from which the following are worth noting:
mercury.catalog.getDeliveryDetails
Commerce Server Basket
mercury.catalog.getDeliveryDetails
To calculate the delivery details for a product bundle the GetDeliveryDetails
processor is added to the pipeline. This processor provides a simple default implementation to calculate the delivery details (e.g. size, weight) for a bundle.
Commerce Server Basket
To keep the Commerce basket up-to-date, e.g. when a bundle no longer exists, the QueryProductBundleInfo
component is inserted in the Commerce pipeline. Make sure that the product bundle commerce pipeline components are registered, by running the Deploy.ps1 that comes with Mercury. The component should be inserted in the basket pipeline at the following location:
Installation
Add the NuGet package Mercury.Feature.ProductBundles
as dependency to your project.
This will automatically add the package Mercury.Foundation.ProductBundles
as dependency.
The following files are included in the packages:
- Configuration files
Feature\Mercury.Feature.ProductBundles.config
Feature\Mercury.Feature.ProductBundles.Serialization.config
Foundation\Mercury.Foundation.ProductBundles.config
- Assets (script) files
assets\js\MercuryProductBundles.js
assets\js\MercuryProductBundles.js.map
- Serialization items
You need to copy;
- configuration files to the
App_config\Include\Mercury
- script files to the
Scripts
- serialization items to the
Serialization
folders of your website.
Configure or patch the Sitecore variable MercurySerializationData
in the Sitecore configuration to the location of your serialization folder. This will ensure the serialization items can be synced using Unicorn.
For example:
<sitecore>
...
<sc.variable name="MercurySerializationData" value="$(dataFolder)\unicorn\mercury\" />
...
</sitecore>
Register QueryProductBundleInfo
the processor to the Commerce Server Basket pipeline:
Windows Registry Editor Version 5.00
; Query Product Bundle Info
[HKEY_CLASSES_ROOT\CLSID\{5CD9F8FE-DDCF-45D6-8D4E-E856E105FD7F}\Implemented Categories]
[HKEY_CLASSES_ROOT\CLSID\{5CD9F8FE-DDCF-45D6-8D4E-E856E105FD7F}\Implemented Categories\{CF7536D0-43C5-11D0-B85D-00C04FD7A0FA}]
[HKEY_CLASSES_ROOT\CLSID\{5CD9F8FE-DDCF-45D6-8D4E-E856E105FD7F}\Implemented Categories\{D82C3499-43C5-11D0-B85D-00C04FD7A0FA}]